package net.tv90.auth.aop;

import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import net.tv90.auth.exception.VerificationException;
import net.tv90.auth.model.AccountToken;
import net.tv90.auth.model.LoginStatus;
import net.tv90.auth.utils.IpUtils;
import net.tv90.auth.utils.TokenUtils;
import net.tv90.auth.utils.UserUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.lang.reflect.Method;
import java.util.Objects;


@Slf4j
@Aspect
@Component
public class VerificationAspect {

    @Autowired
    TokenUtils tokenUtils;

    @Autowired
    UserUtils userUtils;

    @Around("@annotation(net.tv90.auth.aop.annotation.NeedVerify)")
    public Object verify(ProceedingJoinPoint joinPoint) throws Throwable {
        // 从切面织入点处通过反射机制获取织入点处的方法
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        // 获取切入点所在的方法
        Method method = signature.getMethod();
        // 获取request
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = Objects.requireNonNull(attributes).getRequest();
        // 获取请求头
        String token = request.getHeader("Authorization");
        // 获取请求ip
        String ip = IpUtils.getIpAddr(request);
        if (token == null) {
            log.warn("{} 未携带token，登录失败", ip);
            throw new VerificationException("未携带token");
        }
        AccountToken accountToken;
        try {
            accountToken = tokenUtils.parseToken(token);
        } catch (IllegalArgumentException e) {
            log.warn("{} token不合法，登录失败", ip);
            throw new VerificationException("token不合法");
        }
        String username = accountToken.getUsername();
        LoginStatus loginStatus = userUtils.getUserLoginStatus(username);
        String verifyToken = (loginStatus == null) ? null : loginStatus.getToken();
        if (verifyToken == null) {
            log.warn("{}（用户名{}）token已过期，登录失败",ip, username);
            throw new VerificationException("token已过期");
        }
        if (!verifyToken.equals(token)) {
            log.warn("{}（用户名{}）token校验失败，登录失败",ip, username);
            throw new VerificationException("token校验失败");
        }
        return joinPoint.proceed();
    }

}
